/************************************************************************
This file is part of lpc2xxx package for the simpleRTJ virtual machine.

This file is covered by the GNU GPL with the following exception:
  As a special exception, the copyright holders of this library give you permission
  to link this library with independent modules to produce an executable, regardless
  of the license terms of these independent modules, and to copy and distribute the
  resulting executable under terms of your choice, provided that you also meet, for
  each linked independent module, the terms and conditions of the license of that
  module. An independent module is a module which is not derived from or based on
  this library. If you modify this library, you may extend this exception to your
  version of the library, but you are not obligated to do so. If you do not wish
  to do so, delete this exception statement from your version.


THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY,  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL RTJ COMPUTING BE LIABLE FOR ANY CLAIM, DAMAGES
OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

Copyright (c) 2000-2006 RTJ Computing Pty. Ltd. All rights reserved.
***********************************************************************/
package lpc2xxx.hw;


/**
 * Class providing access to Real Time Clock on the LPC21xx.<br>
 * Add your own code to implement additional features if required.
 */
public class RTC
{
    /** Short names for week days: Mon, Tue, etc. */
    public static String[] dayNames = { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" };
    /** Short month names: Jan, Feb, etc. */
    public static String[] monthNames = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct",  "Nov", "Dec" };

    /** RTC hour */
    private final static int HOUR   = 1;
    /** RTC minutes */
    private final static int MIN    = 2;
    /** RTC seconds */
    private final static int SEC    = 3;
    /** RTC year */
    private final static int YEAR   = 4;
    /** RTC month */
    private final static int MON    = 5;
    /** RTC day of month */
    private final static int DAY    = 6;
    /** RTC day of week */
    private final static int DOW    = 7;


    /**
     * Hidden constructor - can't be instantiated. Accessed only via provided
     * static methods.
     */
    private RTC()
    {
    }

    /**
     * Initialises the RTC.
     * @param use32kCrystal set to true if RTC is driven by an external 32.768 kHz crystal.
     * 
     */
    public static native void init(boolean use32kCrystal);

    /**
     * Sets the new time. Use 24 hour format when specifying time.<br>
     * New time will not be accepted if the following is not met:<br>
     * - hour: 0-23<br>
     * - minutes: 0-59<br>
     * - seconds: 0-59
     * @param hour new value for hours (0-23)
     * @param min new value for minutes (0-59)
     * @param sec new value for seconds (0-59)
     */
    public static synchronized void setTime(int hour, int min, int sec)
    {
        setHour(hour);
        setHour(min);
        setHour(sec);
    }

    /**
     * Sets the new hour value in RTC.
     * @param hour new hour value (0-23)
     */
    public static void setHour(int hour)
    {
        set(HOUR, hour);
    }

    /**
     * Sets the new minutes value in RTC.
     * @param min new minutes value (0-59)
     */
    public static void setMin(int min)
    {
        set(MIN, min);
    }

    /**
     * Sets the new seconds value in RTC.
     * @param sec new seconds value (0-59)
     */
    public static void setSec(int sec)
    {
        set(SEC, sec);
    }

    /**
     * Reads the current hour value.
     * @return current hour value.
     */
    public static int getHour()
    {
        return get(HOUR);
    }

    /**
     * Reads the current minutes value.
     * @return current minutes value.
     */
    public static int getMin()
    {
        return get(MIN);
    }
    
    /**
     * Reads the current seconds value.
     * @return current hour value.
     */
    public static int getSec()
    {
        return get(SEC);
    }
    
    /**
     * Creates a string representing current time in 24 hour short format: HH:MM
     * @return current time in short format.
     */
    public static String getShortTime()
    {
        StringBuffer sb = new StringBuffer();
        bin2Str(sb, get(HOUR));
        sb.append(':');
        bin2Str(sb, get(MIN));
        return sb.toString();
    }
    
    /**
     * Creates a string representing current time in 24 hour full format: HH:MM:SS
     * @return current time in full format.
     */
    public static String getFullTime()
    {
        StringBuffer sb = new StringBuffer();
        bin2Str(sb, get(HOUR));
        sb.append(':');
        bin2Str(sb, get(MIN));
        sb.append(':');
        bin2Str(sb, get(SEC));
        return sb.toString();
    }

    /**
     * Sets the new date.<br>
     * @param year new year as four digit number (0-4095)
     * @param mon new month (1-12)
     * @param day new day of month (1-31)
     */
    public static synchronized void setDate(int year, int mon, int day)
    {
        set(YEAR, year);
        set(MON, mon);
        set(DAY, day);
    }

    /**
     * Sets the new year value in RTC.
     * @param year new year value (0-4095)
     */
    public static void setYear(int year)
    {
        set(YEAR, year);
    }

    /**
     * Sets the new month value in RTC.
     * @param mon new month value (1-12)
     */
    public static void setMon(int mon)
    {
        set(MON, mon);
    }

    /**
     * Sets the new day of month value in RTC.
     * @param day new day of month value (1-31)
     */
    public static void setDay(int day)
    {
        set(DAY, day);
    }

    /**
     * Sets the new day of week value in RTC.<br>
     * Available range is 0 to 6, where 0=Monday, 1=Tuesday, etc.
     * @param dow new day of week value (0-6)
     */
    public static void setDoW(int dow)
    {
        set(DOW, dow);
    }

    /**
     * Reads the current year from RTC.
     * @return current year
     */
    public static int getYear(int min)
    {
        return get(YEAR);
    }

    /**
     * Reads the current month from RTC.
     * @return current month
     */
    public static int getMon(int mon)
    {
        return get(MON);
    }

    /**
     * Reads the current day of month from RTC.
     * @return current day of month
     */
    public static int getDay(int day)
    {
        return get(DAY);
    }

    /**
     * Reads the current day of week from RTC.
     * @return current day of week
     */
    public static int getDoW(int dow)
    {
        return get(DOW);
    }

    /**
     * Creates a string representing current date in short format: DD/MM/YYYY
     * @param reverse if set method will return date in format: YYYY/MM/DD
     * @param shortYear if set only last two digits of year are used
     * @return current date in short format.
     */
    public static String getShortDate(boolean reverse, boolean shortYear)
    {
        StringBuffer sb = new StringBuffer();
        int y = get(YEAR);
        if (reverse)
        {
            if (!shortYear)
                bin2Str(sb, (y / 100));
            bin2Str(sb, y );
            sb.append('/');
            bin2Str(sb, get(MON));
            sb.append('/');
            bin2Str(sb, get(DAY));
        }
        else
        {
            bin2Str(sb, get(DAY));
            sb.append('/');
            bin2Str(sb, get(MON));
            sb.append('/');
            if (!shortYear)
                bin2Str(sb, (y / 100));
            bin2Str(sb, y );
        }
        return sb.toString();
    }

    /**
     * Creates a string representing current date in full format: DOW, DD MMM YYYY
     * @return current date in full format.
     */
    public static String getFullDate()
    {
        StringBuffer sb = new StringBuffer();
        
        sb.append(dayNames[get(DOW) % 7]);
        sb.append(", ");
        
        bin2Str(sb, get(DAY));
        sb.append(" ");
        
        sb.append(monthNames[(get(MON) - 1) % 12]);
        sb.append(" ");
        
        int y = get(YEAR);
        bin2Str(sb, (y / 100));
        bin2Str(sb, y );
        
        return sb.toString();
    }

    /**
     * Converts two digit integer value into ASCII characters and appends it to
     * the provided StringBuffer.
     * @param sb StringBuffer that will receive converted value
     * @param v integer value of which two digits will be converted to ASCII chars
     */
    private static void bin2Str(StringBuffer sb, int v)
    {
        sb.append((char)(0x30 + ((v / 10) % 10)));
        sb.append((char)(0x30 + (v % 10)));
    }

    /**
     * Sets the new value for specified RTC date/time register.
     * @param id identifies date/time register, use provided RTC_xxx constants.
     * @param val new value that will be written to date/time register
     */
    private static native void set(int id, int val);

    /**
     * Get the current value from specified RTC date/time register.
     * @param id identifies date/time register, use provided RTC_xxx constants.
     * @return current value of the specified date/time register.
     */
    private static native int get(int id);
}
